package com.lifang.framework.aop.aspectj;

import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class MethodSignatureImpl implements MethodSignature {

    private Method method;

    private MethodInvocation methodInvocation;

    public MethodSignatureImpl(MethodInvocation methodInvocation) {
        this.methodInvocation = methodInvocation;
        this.method = methodInvocation.getMethod();
    }

    @Override
    public Class getReturnType() {
        return this.method.getReturnType();
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public Class[] getParameterTypes() {
        return this.method.getParameterTypes();
    }

    @Override
    public String[] getParameterNames() {
        throw new IllegalArgumentException("unsupported operation");
    }

    @Override
    public Class[] getExceptionTypes() {
        return this.method.getExceptionTypes();
    }

    @Override
    public String toShortString() {
        return toString(false, false, false, false);
    }

    @Override
    public String toLongString() {
        return toString(true, true, true, true);
    }

    @Override
    public String getName() {
        return this.method.getName();
    }

    @Override
    public int getModifiers() {
        return this.method.getModifiers();
    }

    @Override
    public Class<?> getDeclaringType() {
        return this.method.getDeclaringClass();
    }

    @Override
    public String getDeclaringTypeName() {
        return this.method.getDeclaringClass().getName();
    }

    private String toString(boolean includeModifier, boolean includeReturnTypeAndArgs, boolean useLongReturnAndArgumentTypeName, boolean useLongTypeName) {
        StringBuilder sb = new StringBuilder();
        if (includeModifier) {
            sb.append(Modifier.toString(getModifiers()));
            sb.append(" ");
        }
        if (includeReturnTypeAndArgs) {
            appendType(sb, getReturnType(), useLongReturnAndArgumentTypeName);
            sb.append(" ");
        }
        appendType(sb, getDeclaringType(), useLongTypeName);
        sb.append(".");
        sb.append(getMethod().getName());
        sb.append("(");
        Class<?>[] parametersTypes = getParameterTypes();
        appendTypes(sb, parametersTypes, includeReturnTypeAndArgs, useLongReturnAndArgumentTypeName);
        sb.append(")");
        return sb.toString();
    }

    private void appendType(StringBuilder sb, Class<?> type, boolean useLongTypeName) {
        if (type.isArray()) {
            appendType(sb, type.getComponentType(), useLongTypeName);
            sb.append("[]");
        } else {
            sb.append(useLongTypeName ? type.getName() : type.getSimpleName());
        }
    }

    private void appendTypes(StringBuilder sb, Class<?>[] types, boolean includeArgs, boolean useLongReturnAndArgumentTypeName) {
        if (includeArgs) {
            for (int size = types.length, i = 0; i < size; i++) {
                appendType(sb, types[i], useLongReturnAndArgumentTypeName);
                if (i < size - 1) {
                    sb.append(",");
                }
            }
        } else {
            if (types.length != 0) {
                sb.append("..");
            }
        }
    }
}
